#' Fisher's combined test
#'
#' @param pval Vector of outcome p-values
#' @export
#' @return List with the following elements:
#' \describe{
#' \item{b}{MR estimate}
#' \item{se}{Standard error}
#' \item{pval}{p-value}
#' }
fishers_combined_test <- function(pval) {
  pval <- pval[is.finite(pval) & pval <= 1 & pval >= 0]
  index <- pval == 0
  if (any(index)) {
    warning("p-values of 0 are unreliable in Fisher's combined test.")
    pval[index] <- 1e-50
  }
  p <- stats::pchisq(-2 * sum(log(pval)), df = 2 * length(pval), lower.tail = FALSE)
  return(list(pval = p, nsnp = length(pval)))
}


#' Get list of available p-value enrichment methods
#'
#' @export
#' @return Data frame
enrichment_method_list <- function() {
  a <- list(
    list(
      obj = "fishers_combined_test",
      name = "Fisher's combined test",
      PubmedID = "",
      Description = ""
    )
  )
  a <- lapply(a, as.data.frame)
  a <- plyr::rbind.fill(a)
  a <- as.data.frame(lapply(a, as.character), stringsAsFactors = FALSE)
  return(a)
}


#' Perform enrichment analysis
#'
#'
#' @param dat Harmonised exposure and outcome data. Output from [harmonise_data()].
#' @param method_list List of methods to use in analysis. Default is \code{enrichment_method_list()$obj}.
#' See [enrichment_method_list()] for details.
#'
#' @export
#' @return data frame
enrichment <- function(dat, method_list = enrichment_method_list()$obj) {
  res <- plyr::ddply(dat, c("id.exposure", "id.outcome"), function(x1) {
    # message("Performing enrichment analysis of '", x$id.exposure[1], "' on '", x$id.outcome[1], "'")

    x <- subset(x1, !is.na(pval.outcome))
    if (nrow(x) == 0) {
      message(
        "No outcome p-values for analysis of '",
        x1$id.exposure[1],
        "' on '",
        x1$id.outcome[1],
        "'"
      )
      return(NULL)
    }
    res <- lapply(method_list, function(meth) {
      get(meth)(x$pval.outcome)
    })
    methl <- enrichment_method_list()
    enrichment_tab <- data.frame(
      outcome = x$outcome[1],
      exposure = x$exposure[1],
      method = methl$name[methl$obj %in% method_list],
      nsnp = sapply(res, function(x) x$nsnp),
      pval = sapply(res, function(x) x$pval)
    )
    enrichment_tab <- subset(enrichment_tab, !is.na(pval))
    return(enrichment_tab)
  })
  return(res)
}
